/**
  ******************************************************************************
  * @file    mg_test_ble.c
  * @author  
  * @version V1.1
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT 2020 Shanghai Macrogiga Electronics</center></h2>
  *
  ******************************************************************************
  */
  
#include "mg_driver_ble.h"
#include "mg_ble_control.h"
#include "mg_driver_gpio.h"
#include "mg_driver_int.h"
#include "mg_driver_sys.h"
#include "mg_driver_uart.h"

#include <string.h>

void toggle_led_io(void);

u8 uart_rx_buf[20];
u8 uart_rx_pos = 0;

void direct_test_init(void)
{
    uart_rx_pos = 0;
}
#define DUT_FW_VERSION  0x10 /*1.0*/
void HciSendData(u8* data, u8 len);
void direct_test_uart_init(void)
{
    u8 HciReset[8] = {0x01,0x03,0x0c,0x00};
    u8 VenderInfo[5] = {0x01,0x01,0xFc,0x01,DUT_FW_VERSION};
    direct_test_init();
    
    //enable the irq bit
    NVIC_EnableIRQ(INT_MASK_BIT_UART);
    
    UART_Set_baudrate(9600/*115200*/);    
//    UART_Enable_FlowControl();
#ifdef UART_2_WIRE_FORMAT
    memcpy(HciReset,"2-wire",6);
    HciSendData(HciReset,6);
#else    
    HciSendData(HciReset,4);
    HciSendData(VenderInfo,5);
#endif
}

//void ParserDirectTestCmd(u8* uartCmd);
void ParserBleHciCmd(u8* uart_rx_buf);
void ParserDirectTestCmd(u8* uartCmd);//UART_2_WIRE_FORMAT
//uart irq handle
void UART_IRQHandler(void)
{
//    static char iic = 0;
    
//    if(UART_ADDR->IIR_FCR/*clear the RX interrupt*/) iic++;
    
    while(UART_Get_RX_Flag())
    {
//        UART_SendOneByte(UART_ReceiveByte());
       uart_rx_buf[uart_rx_pos++] = UART_ReceiveByte();
        
#ifdef UART_2_WIRE_FORMAT
       if(uart_rx_pos >= 2)//full cmd
       {
          uart_rx_pos = 0; //renew
          ParserDirectTestCmd(uart_rx_buf);
       }
#else
        if(uart_rx_pos >= 4)//01 1E 20 03 xx yy zz
        {
            if(uart_rx_pos >= uart_rx_buf[3] + 4)
            {
                uart_rx_pos = 0; //renew
                ParserBleHciCmd(uart_rx_buf);
            }
        }
#endif
    }
}

void toggle_led_io_init(void)
{
    GPIO_InitTypeDef cfg;
    
//    return;
    
    GPIO_FunctionSelect(GPIO_MAP_PIN_A0,GPIO_MAP_PIN_FUNC1);
    
    cfg.GPIO_Mode = GPIO_Mode_Out_PP;
    cfg.GPIO_Pin  = GPIO_PIN_0;
    GPIO_Init(GPIO, &cfg);
    
    GPIO->DATA_OUT_SET = GPIO_PIN_0;
    
    toggle_led_io();
}

void toggle_led_io(void)
{
    static char high = 1;
    
    if(high)GPIO->DATA_OUT_SET = GPIO_PIN_0;
    else GPIO->DATA_OUT_CLEAR = GPIO_PIN_0;
    
    high = !high;
}

/////////////////////////////////////////////////////////////////////////
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
u8 MgBle_DirctTestTx_Run(u8);
u8 MgBle_DirctTestRx_Run(void); //rx package returns 1
void MgBle_DirctTestTxRx_Init(BLE_ADV_DATA_INFO *cfg,u8);

u8* get_long_rx_pkt_buf(void);

#define DIRECT_TEST_RX  0x00
#define DIRECT_TEST_TX  0x01

void init_direct_test_long_buff(void);
u8* get_long_tx_pkt_buf(void);

#define PKT_PRBS9    0x00
#define PKT_11110000 0x01
#define PKT_10101010 0x02
#define PKT_PRBS15   0x03
#define PKT_11111111 0x04
#define PKT_00000000 0x05
#define PKT_00001111 0x06
#define PKT_01010101 0x07

#define PKT_TYPE0    0x00
#define PKT_TYPE1    0x01
#define PKT_TYPE2    0x02
#define PKT_TYPE3    0x03
#define PKT_TYPE4    0x04
#define PKT_TYPE5    0x05
#define PKT_TYPE6    0x06
#define PKT_TYPE7    0x07

void generate_PRBS9(u8* out)//max 255 bytes, X9+X5+1=0
{
    u16 v = 0x1FF,shift_v;
    u16 i,j;
    u8 t = 0;
    
//    for(i = 0 ; i < 255 ; i ++)*out++ = i; return;
    
    for(i = 0 ; i < 255*8 ; i +=8)
    {
        for(j = 0 ; j < 8 ; j ++)
        {
            t >>= 1;
            shift_v = v & 0x0001;
            t |= (shift_v << 7);
            
            v >>= 1;
            v |= (((shift_v + (v >> 3)) & 0x01) << 8);
        }        
        //save the byte
        *out++ = t; //v
        
        //init the byte
        t = 0;
    }
}

void generate_PRBS15(u8* out)//max 255 bytes, X15+x14+1=0
{
    u16 v = 0x7FFF,shift_v;
    u16 i,j;
    u8 t = 0;
    
    for(i = 0 ; i < 255*8 ; i +=8)
    {
        for(j = 0 ; j < 8 ; j ++)
        {
            t >>= 1;
            shift_v = v & 0x0001;
            t |= (shift_v << 7);
            
            v >>= 1;
            v |= (((shift_v + (v)) & 0x01) << 14);
        }        
        //save the byte
        *out++ = t;
        
        //init the byte
        t = 0;
    }
}

void set_bqb_test_package_data(u8 pkt_type_ID, u8 len)
{
    u8* tx_buf = get_long_tx_pkt_buf();
    
    tx_buf[0] = pkt_type_ID;
    tx_buf[1] = len;
    
    switch(pkt_type_ID)
    {
        case PKT_PRBS9:
            generate_PRBS9(tx_buf+2);
            break;
        
        case PKT_11110000:
            memset(tx_buf+2,0x0F,len);
            break;
        
        case PKT_10101010:
            memset(tx_buf+2,0x55,len);
            break;
        
        case PKT_PRBS15:
            generate_PRBS15(tx_buf+2);
            break;
        
        case PKT_11111111:
            memset(tx_buf+2,0xFF,len);
            break;
        
        case PKT_00000000:
            memset(tx_buf+2,0x00,len);
            break;
        
        case PKT_00001111:
            memset(tx_buf+2,0xF0,len);
            break;
        
        case PKT_01010101:
            memset(tx_buf+2,0xaa,len);
            break;
        
        default:break;
    }
}

u8 DirectTestChMap(u8 test_ch)
{
    const u8 ch_map[40] = {37,0,1,2,3, 4,  5, 6, 7, 8, 9,10,38,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,39};
                 //2402 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80
    if(test_ch < 40)return ch_map[test_ch];
    else return 0;
}

u16 RX_COUNT_LE_TEST = 0;

extern u8 TestStatus; //idle(0) means exit

void LE_Packet_Report_Event(u16 number);
void mg_writeReg(u8 reg, const u8 value);
void mg_readBuf(u8 reg, u8 *pBuf, u8 len);
void radio_setBleAddr(u8 *addr/*6Bytes*/);
void radio_setModeDisable(void);

const u8 ch_map[40] = {37,0,1,2,3, 4,  5, 6, 7, 8, 9,10,38,11,12,13,14,15,
        16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,39};

void test_direct_test(u8 RxModeFlag,u8 dut_channel, u8 pkt_typeIdx, u8 tx_pkt_len)
{
    u8 adv[] = {2,1,6,9,9,'m','g','1','7','x','B','Q','B'};    
    
    BLE_ADV_DATA_INFO slave_cfg;
    su32 interval;
    
    slave_cfg.advType = 0xff;//ADV_NONCONN_IND;//ADV_IND;
    slave_cfg.advData = adv;
    slave_cfg.advDataLen = sizeof(adv);
    slave_cfg.interval = 160*2; //200ms, not used
    
    mg_writeReg(0x20,0/*scramble_off*/);
    
    long_pkt_rx_tx_init();
    set_bqb_test_package_data(pkt_typeIdx,tx_pkt_len);
    radio_setLongPktCfg(2);
    if(!RxModeFlag)//Tx mode test
    {
        if(pkt_typeIdx == 0x0F)//carrier tone test case, MG defined case ONLY!!! early break here
        {
            if(dut_channel<=39)radio_startCarrierTone(ch_map[dut_channel]);
            while(TestStatus);//wait stop
            radio_endCarrierTone();
            
            return; //early break here!!!!
        }
        
        if(*((u8*)(get_long_tx_pkt_buf()+1))<= 37)radio_setLongPktCfg(0/*no wait*/); //no delay for short package test case
        else radio_setLongPktCfg(50);//delay 50us

        //get the tx interval
        if(*((u8*)(get_long_tx_pkt_buf()+1))<= 37)
        {
            interval = 625;//us
        }
        else if(*((u8*)(get_long_tx_pkt_buf()+1))<= 115)
        {
            interval = 1250;//us
        }
        else if(*((u8*)(get_long_tx_pkt_buf()+1))<= 193)
        {
            interval = 1875;//us
        }
        else//biggest package
        {
            interval = 2500;//us
        }
        
        {
          u8* tx_buf_t = get_long_tx_pkt_buf();
          slave_cfg.advType = tx_buf_t[0];
          slave_cfg.advDataLen = tx_buf_t[1];
        }
        
        MgBle_DirctTestTxRx_Init(&slave_cfg,DIRECT_TEST_TX);
        init_direct_test_long_buff();//setting the offset
        radio_setBleAddr(get_long_tx_pkt_buf()+2);//fill the first 6 byts to addr    
        radio_setChannel(DirectTestChMap(dut_channel));     
        radio_seg_tx_start(0);//start fill the first 32 bytes
        
        //fill data to adv header
        {
            u8 *tx_data = get_long_tx_pkt_buf();
            pdu_hdr_t header_;
            header_.type = tx_data[0];
            header_.len = tx_data[1];
            radio_setAdvHeader(0,header_);
        }
        radio_setIntervalTestMode(interval/*us*/); //setting the interval

        radio_setWakeupNow(); //wakeup and start tx.....
        
{ //continue wave form data tx mode with set byte
//    int radio_continue_wave_byte(u8 Data);//cfg continue wave data if any, debug&test purpose ONLY!
//    radio_continue_wave_byte(0x55);
}       

#if 0
        while(/*1*/TestStatus)
        {
            MgBle_DirctTestTx_Run(0); 
        } 
        radio_setModeDisable();//end of test mode
#else
        toggle_led_io();
        while(1)
        {
            if(0 == MgBle_DirctTestTx_Run(TestStatus))break;
        }
        toggle_led_io();
#endif
    }    
    else //Rx test
    {
        MgBle_DirctTestTxRx_Init(&slave_cfg,DIRECT_TEST_RX);

        radio_setChannel(DirectTestChMap(dut_channel));
        init_direct_test_long_buff();//setting the offset
        
//        radio_setIntervalTestMode(1000*20/*us*/);//not used this value in continue direct test mode
        
        memset(get_long_rx_pkt_buf(),0,257);
        radio_setWakeupNow(); //wakeup and start Rx.....
        
        while(/*1*/TestStatus)
        {
            RX_COUNT_LE_TEST += MgBle_DirctTestRx_Run();
        }
        
        if(1)//old, it is the final OK version @20200826
        { //catch the un-affected cfg point, about 10~20us Redundance
            u8 _reg[4];
            
            //first dectect the anchor point
            while(1)
            {
                mg_readBuf(0x13,_reg,4);
                if(!(_reg[3] & 0x40)) //bit6: framer_st_WAIT_RX
                    break;
            }
            while(1)
            {
                mg_readBuf(0x13,_reg,4);
                if(_reg[3] & 0x40) //bit6: framer_st_WAIT_RX
                    break;
            }
            
            //second time, confirm the cfg point
            while(1)
            {
                mg_readBuf(0x13,_reg,4);
                if(!(_reg[3] & 0x40)) //bit6: framer_st_WAIT_RX
                    break;
            }
            while(1)
            {
                mg_readBuf(0x13,_reg,4);
                if(_reg[3] & 0x40) //bit6: framer_st_WAIT_RX
                    break;
            }
        }
        else //new rx method, drop @ 20200826
        {
            power_down_then_up();//defined in bt lib
        }
        
        radio_setModeDisable();//end of test mode

    }
}

#define UART_TEST_RESET   0
#define UART_TEST_RX      1
#define UART_TEST_TX      2
#define UART_TEST_END     3

#define TEST_IDLE         0
#define TEST_RX_ON        1
#define TEST_TX_ON        2
#define TEST_RESET        0

u8 TestStatus = TEST_IDLE;

u8 Test_Pkt_size_Hi = 0;
u8 Test_freq_ch = 0;
u16 Test_Pkt_total_size;
u8 Test_Pkt_type = 0;

u8 *my_ble_addr;

#define DUT_TX_MODE 0x00
#define DUT_RX_MODE 0x01

void show_end_of_test_result(void);

void test_ble_direct_test(void)
{
    MgBle_EnableDirectTestMode();
    
    toggle_led_io_init();
    
    MgBle_Init(TXPWR_0DBM, &my_ble_addr);//TXPWR_0DBM,TXPWR__18DBM
    
    NVIC_IrqClearPendingIRQ(0);//seg pending irq
    NVIC_IrqClearPendingIRQ(2);//sleep pending irq
    
//    NVIC_EnableIRQ(INT_MASK_BIT_BB_SEG);
//    NVIC_EnableIRQ(INT_MASK_BIT_BB);
#if 1
    direct_test_uart_init(); //enable uart functions for auto rf test
#else
//chip test
    TestStatus = UART_TEST_TX;
    Test_freq_ch = 0; //channel 37
    Test_Pkt_total_size = 37; //255;//193;//115;//37;
    Test_Pkt_type = 1;
    {
        u8 adv_AA[4] = {0xD6, 0xBE, 0x89, 0x8E}; //adv AA addr
        setDirectTestAA(adv_AA); //test purpose ONLY!!!
    }
#endif
    while(1)
    {
        while(!TestStatus) //idle wait
        {
            
        }
    
        if(TestStatus == UART_TEST_RX)
        {
            test_direct_test(DUT_RX_MODE,Test_freq_ch, Test_Pkt_type,Test_Pkt_total_size);
        }
        else
        {
            test_direct_test(DUT_TX_MODE,Test_freq_ch, Test_Pkt_type,Test_Pkt_total_size);
        }
        
        show_end_of_test_result();
    }
}

//////////////////////////////////////////////////////


#define UNKNOWN_HCI_COMMAND               0x0001
#define HCI_Reset                         0x0003
#define HCI_Read_BD_ADDR                  0x0009
#define HCI_LE_Receiver_Test              0x001D
#define HCI_LE_Transmitter_Test           0x001E
#define HCI_LE_Test_End                   0x001F

#define Command_Complete_Event  0x0E  /*Num_HCI_Command_Packets,Command_Opcode, Return_Parameters*/
#define Command_Status_Event    0x0F  /*Status,Num_HCI_Command_Packets,Command_Opcode*/
#define Number_Of_Completed_Packets_Event 0x13 /*Number_of_Handles,Connection_Handle[i],HC_Num_Of_Completed_Packets[i]*/

u8 Num_HCI_Command_Packets = 5; /*number of HCI cmd */

//send the data/*event, ACL*/controller to host through hci interface
void HciSendData(u8* data, u8 len) 
{
    while(len)
    {
        UART_SendOneByte(*data ++);
        while(!UART_Get_TX_Flag()); //wait for empty
        len --;
    }
}

static u8 s_event[68+4];
void CmdCompleteEvent(u8* cmd/*OCF OGF*/, u8* par, u8 parLen)
{   
    s_event[0] = 0x04;
    s_event[1] = Command_Complete_Event;
    //to check whether the cmd is masked away
    
    s_event[2] = parLen+3;//len
    s_event[3] = Num_HCI_Command_Packets;
    s_event[4] = cmd[0];
    s_event[5] = cmd[1];
    memcpy(s_event+6,par, parLen);
    
    HciSendData(s_event,parLen+6);
}

void show_end_of_test_result(void)
{
#ifdef UART_2_WIRE_FORMAT
    LE_Packet_Report_Event(RX_COUNT_LE_TEST);
#else
    
    u8 result[4];
                    
    result[0] = 0;//success
    result[1] = RX_COUNT_LE_TEST;//Number_Of_Packets
    result[2] = RX_COUNT_LE_TEST>>8;
    CmdCompleteEvent(uart_rx_buf+1,result,3);
#endif
}

void ParserBleHciCmd(u8* uart_rx_buf)
{
    u16 OCF,OGF;
    u8* data,status;
    
    if(uart_rx_buf[0] != 0x01)return; //error found
    
    OGF = (uart_rx_buf[2]>>2) & 0x3F;
    
    OCF = uart_rx_buf[2] & 0x03;
    OCF <<= 8;
    OCF |= uart_rx_buf[1];
    
    data = uart_rx_buf + 4;
    
    switch(OGF)
    {
        case 0x03://HCI Control and Baseband Commands
            switch(OCF)
            {
                case HCI_Reset:
                    TestStatus = 0; //end of RF testing
                    status = 0;
                    CmdCompleteEvent(uart_rx_buf+1,&status,1);
                    break;
                
                default:
                    status = UNKNOWN_HCI_COMMAND;
                    CmdCompleteEvent(uart_rx_buf+1,&status,1);
                    break;
            }
        break;
            
        case 0x04:
            switch(OCF)
            {
                case HCI_Read_BD_ADDR:
                {
                    u8 addr[6+1];//first byte is the status
                    addr[0] = 0;//success
                    memcpy(addr+1,my_ble_addr,6);
                    CmdCompleteEvent(uart_rx_buf+1,addr,7);
                }
                    break;
                
                default:
                    status = UNKNOWN_HCI_COMMAND;
                    CmdCompleteEvent(uart_rx_buf+1,&status,1);
                    break;
            }
        break;
        
        case 0x08: //LE Controller Commands
            switch(OCF)
            {
                case HCI_LE_Receiver_Test:
                {
                    Test_freq_ch = data[0];
                    RX_COUNT_LE_TEST = 0;
                    
                    status = 0; //success
                    CmdCompleteEvent(uart_rx_buf+1,&status,1);
                    
                    TestStatus = 1; //Rx test start
                }
                    break;
                
                case HCI_LE_Transmitter_Test:
                    
                    RX_COUNT_LE_TEST = 0;
                
                    //data[0]:tx channel
                    //data[1]:tx data len, 0-0x25 ???
                    //data[2]:Packet_Payload type ID
                    Test_Pkt_total_size = data[1];
                    Test_Pkt_type = data[2];
                    Test_freq_ch = data[0];
                
                    status = 0; //success
                    CmdCompleteEvent(uart_rx_buf+1,&status,1);
                
                    TestStatus = 2; //Tx test start
                
                    break;
                
                case HCI_LE_Test_End:
                {
                    u8 result[4];
                    
                    if(!TestStatus)
                    {
                        result[0] = 0;//success
                        result[1] = RX_COUNT_LE_TEST;//Number_Of_Packets
                        result[2] = RX_COUNT_LE_TEST>>8;
                        CmdCompleteEvent(uart_rx_buf+1,result,3);
                    }
                    
                    TestStatus = 0; //end of RF testing
                }
                    break;
                
                default:
                    status = UNKNOWN_HCI_COMMAND;
                    CmdCompleteEvent(uart_rx_buf+1,&status,1);
                    break;
            }
        break;
        
        case 0x3F://vendor specific cmd
            switch(OCF)
            {
                case 0x01: //01 01 FC 01 pwr : RF Power setting
                    status = 0; //success
                    radio_setPaGain(uart_rx_buf[4]);
                    break;
                
                default:
                    status = UNKNOWN_HCI_COMMAND;
                    break;
            }
            
            CmdCompleteEvent(uart_rx_buf+1,&status,1);
        break;
        
        default:
            status = UNKNOWN_HCI_COMMAND;
            CmdCompleteEvent(uart_rx_buf+1,&status,1);
            break;
    }
}

void slave_app_cfg(void)
{
    
}
